package juc.blockqueue.delayqueue;

/**
 * @ClassName DelayQueueExample
 * @PackageName juc.blockqueue.delayqueue
 * @projectName myThread
 * @Description TODO
 * @Author games
 * @Date 2025/9/4 下午1:20
 * @Version 1.0
 */

import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.BlockingQueue;

/**
 * DelayQueue 是一个无界的阻塞队列，只有在延迟期满时才能从中获取元素。它专门用于放置实现了 Delayed 接口的对象。
 * 基本特性
 * 无界队列：理论上容量无限制（受内存限制）
 * 延迟获取：只有当元素的延迟时间到期后才能被取出
 * 阻塞特性：当没有到期元素时，获取操作会阻塞
 * 线程安全：内部使用锁机制保证多线程安全
 * 元素要求：队列中的元素必须实现 Delayed 接口
 * <p>
 * <p>
 * <p>
 * put(E e)：插入元素，由于是无界队列，不会阻塞
 * offer(E e)：插入元素，立即返回 true
 * add(E e)：插入元素，与 offer 功能相同
 * 移除操作
 * take()：获取并移除到期元素，没有到期元素时阻塞
 * poll()：获取并移除到期元素，没有到期元素时返回 null
 * poll(long timeout, TimeUnit unit)：获取并移除到期元素，可设置超时时间
 * 检查操作
 * peek()：返回到期元素但不移除，没有到期元素时返回 null
 * size()：返回队列中元素总数（包括未到期的）
 * remove(Object o)：移除指定元素
 */
class DelayedTask implements Delayed {
    private final long startTime;
    private final String name;

    public DelayedTask(long delay, String name) {
        this.startTime = System.currentTimeMillis() + delay;
        this.name = name;
    }

    @Override
    /**
     * 获取剩余延迟时间
     * @param unit 时间单位参数，用于返回结果的时间单位
     * @return 转换为指定时间单位的延迟时间
     */
    public long getDelay(TimeUnit unit) {
        // 计算当前时间与开始时间的差值
        long diff = startTime - System.currentTimeMillis();
        // 将时间差转换为指定时间单位并返回
        return unit.convert(diff, TimeUnit.MILLISECONDS);
    }

    @Override
    public int compareTo(Delayed o) {
        if (this.getDelay(TimeUnit.MILLISECONDS) < o.getDelay(TimeUnit.MILLISECONDS)) return -1;
        else if (this.getDelay(TimeUnit.MILLISECONDS) > o.getDelay(TimeUnit.MILLISECONDS)) {
            return 1;
        } else {
            return 0;
        }
    }

    @Override
    public String toString() {
        return name;
    }
}

public class DelayQueueExample {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<DelayedTask> queue = new DelayQueue<>();
        queue.put(new DelayedTask(2000, "Task 1"));
        queue.put(new DelayedTask(1000, "Task 2"));

        while (!queue.isEmpty()) {
            System.out.println(queue.take());
        }
    }
}